package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
)

func reqDataHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w,"请求url：", r.URL.Path)
    fmt.Fprintln(w,"请求查询字符串：", r.URL.RawQuery)
    fmt.Fprintln(w,"请求请求头：", r.Header)
    fmt.Fprintln(w,"请求请求头：", r.Header["Authorization"][0])
	fmt.Fprintln(w,"请求地址：", r.Host)
	r.Host = "www.a.com"
	fmt.Fprintln(w,"请求地址：", r.Host)
	//go请求头中没有Host值，因此如果要设置host值，因此不能使用Set方法，直接使用r.Host = ""
	//fmt.Fprintln(w,"请求请求头host：", r.Header.Get("Host"))

	//Host添加到header也不可行
	//w.Header().Add("Host", r.Host)
	//fmt.Fprintln(w,"请求请求头Accept：", r.Header.Get("Accept"))  //或者map取值r.Header["Host"]

	fmt.Fprintln(w,"请求协议：", r.Proto)
	fmt.Fprintln(w,"请求方法：", r.Method)
	fmt.Fprintln(w,"请求体长度：", r.ContentLength)
    fmt.Fprintln(w,"请求ip地址：", r.RemoteAddr)
    fmt.Fprintln(w,"请求RequestURI ：", r.RequestURI )  //url路径和参数


	//请求参数
	//在调用Form之前必须先调用ParseForm，使用form则Body不可用，否则取不到值
	//err := r.ParseForm()
	//if err!=nil{
	//	fmt.Println(err)
	//}
	//username := r.Form.Get("username")
	//password := r.Form.Get("password")
	////当请求体中(Post)请求字段和url(Get)参数中有相同字段，那么该字段都能获取到，且请求体中数据在前
	//fmt.Fprintln(w, "请求参数：", username,password)
	////请求体和url中都能获取到
	//fmt.Fprintln(w, "请求参数：", r.Form)
	////只获取请求体中数据
	//fmt.Fprintln(w, "请求参数：", r.PostForm)

	//获取请求体
	//length := r.ContentLength
	//body:=make([]byte, length)
	////将请求体中的内容读到body中
	//r.Body.Read(body)
	//fmt.Fprintln(w, "请求体：", string(body))


	pBody := make(map[string]interface{})
	b, _ := ioutil.ReadAll(r.Body)
	json.Unmarshal(b, &pBody)
	fmt.Fprintln(w, "请求体：", pBody["a"], pBody["b"])

	//FormValue和PostFormValue会自动调用ParseForm
	fmt.Fprintln(w,"请求参数:", r.FormValue("username"))
	fmt.Fprintln(w,"请求参数Post:", r.PostFormValue("username"), r.PostFormValue("password"))
}

func RedirectHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Location","http://"+r.Host+"/req")  //必须在WriteHeader之前
    w.WriteHeader(302)

}

type User struct {
	Name string `json:"name"`
	Password string `json:"password"`
}

func JsonHandler(w http.ResponseWriter, r *http.Request) {
	//设置响应头
    //w.Header().Set("Content-Type", "application/json")
    data :=make(map[string]interface{})
    user :=User{
    	Name: "go",
    	Password: "12345",
	}
	data["msg"] = http.StatusOK
	data["user"] = user
	//jsonBytes, _ := json.Marshal(data)
	//w.Write(jsonBytes)
	tpl, _:=template.ParseFiles("./netHttp/tpl.html","./netHttp/models.html")
	err := tpl.Execute(w, data)
	if err != nil {
		fmt.Println(err)
	}
}

func UploadHandler(w http.ResponseWriter, r *http.Request) {
	file, header, err := r.FormFile("file")
	if err==nil{
		fmt.Println(header.Filename)
		bytes, err := ioutil.ReadAll(file)
		if err==nil{
			//fmt.Fprintln(w,string(bytes))
			f, err := os.OpenFile("./netHttp/"+header.Filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
			if err==nil{
				defer f.Close()
				writer := bufio.NewWriter(f)
				writer.Write(bytes)
				// 因为writer带缓存，在调用WriterString时，内容是先写入缓存的，需要使用flush方法，将
				//缓冲的数据真正写入到文件中
				writer.Flush()
			}
		}
	}
}

//模板渲染
func TplHandler(w http.ResponseWriter, r *http.Request) {
    //tpl, err:=template.ParseFiles("./netHttp/tpl.html")
	//if err!=nil{
	//	fmt.Println(err)
	//}
	//Must自动处理异常
	//tpl:=template.Must(template.ParseFiles("./netHttp/tpl.html"))
	//可同时解析多个模板文件，但渲染只会是第一个，可以使用ExecuteTemplate指定渲染模板
	tpl:=template.Must(template.ParseFiles("./netHttp/tpl2.html","./netHttp/tpl.html"))
	//err := tpl.Execute(w, "这是渲染内容")
	err := tpl.ExecuteTemplate(w, "tpl.html","这是渲染内容")
	if err!=nil{
		fmt.Println("Execute error",err)
	}

	//匹配解析html
	//template.ParseGlob("templates/*.html")

	//更改模板引擎标识符，如Vue等前端框架标识符和模板标识符冲突
	//template.New("test").Delims("{[", "]}").ParseFiles("./t.html")
}

func main() {
	http.HandleFunc("/req",reqDataHandler)
	http.HandleFunc("/redirect",RedirectHandler)
	http.HandleFunc("/json",JsonHandler)
	http.HandleFunc("/up",UploadHandler)
	http.HandleFunc("/tpl",TplHandler)
	//处理静态文件
	http.Handle("/statics/", http.StripPrefix("/statics/", http.FileServer(http.Dir("./netHttp/statics"))))

	http.ListenAndServe(":8000",nil)
}